/*****************************///////////////////////////
                              /*        MONOPOLY       */
                              ///////////////////////////**********************************/

/* ******************************************************************************
 * Contributors:     Federico Commisso Amita Singh, and Kretika Gupta
 * Class:            CAP 4403/CAP 6402
 * Instructor:       Dr. Paul Fishwick
 * Project:          Monopoly Game to illustrate the inner working of a Linked-List
 *
 * Concept:
 *     The Linked List data structure is represented by the player's and the bank's
 *     record of properties.
 * ******************************************************************************/

/*****************************///////////////////////////
                              /*     DATA STRUCTURES   */
                              ///////////////////////////**********************************/

/*** GAME MODES ***/
boolean START_BANK_WITH_HOUSES = true; 
boolean START_PLAYER_1_WITH_HOUSES = true;
boolean START_PLAYER_2_WITH_HOUSES = true;


/*** ****************************** ***/                              
LinkedList Player_1 = new LinkedList();
LinkedList Player_2 = new LinkedList();
LinkedList Bank = new LinkedList();
House INSERTION_HOUSE;
House DELETION_HOUSE;
int INSERTION_STEP = 0;
int DELETION_STEP = 0;
boolean INSERTING_TO_BANK = false;
boolean DELETING_FROM_BANK = false;
int PLAYER_1_LIST_X = 100;
int PLAYER_1_LIST_Y = 355;
int PLAYER_2_LIST_X = 100;
int PLAYER_2_LIST_Y = 490;
int BANK_LIST_X = 100;
int BANK_LIST_Y = 620;
/*** ***************************** ***/ 

/* Scene Graphics */
PFont serif36, serif24, serif16;
final int TEXT_COL = #291C19;
final int BANKRUPT_COL = #DB0000;
final int BANK = 3;
final int NONE = 0;

PImage gameboard,
       house,
       buy_button, buy_button_pressed,
       sell_button, sell_button_pressed,
       roll_button, roll_button_pressed,
       turn_over_button, turn_over_button_pressed,
       inactive_button,
       node_selector,
       player_1, player_2,
       dice_null,
       dice_1, dice_2, dice_3, dice_4, dice_5, dice_6,
       arrow_link;

/* Button positions */
final int ROLL_BUTTON_X = 650;
final int ROLL_BUTTON_Y = 155;
final int BUY_BUTTON_X = 400;
final int BUY_BUTTON_Y = 215;
final int SELL_BUTTON_X = 400;
final int SELL_BUTTON_Y = 215;
final int TURN_OVER_BUTTON_X = 400;
final int TURN_OVER_BUTTON_Y = 270;
final int DICE_Y_POS = 40;
final int DICE_X_POS = 675;
final int PLAYER_TURN_X = 430;
final int PLAYER_TURN_Y = 35;

/* Text poistions */
PVector TEXT_FIELD_POS = new PVector(330, 80);
int LS = 20; // Line Spacing

/* Game States */
int roll;
int Turn = 1; // player 1 starts first
int roundCount = 0;

int REWARD = 200;
int player_1_money = 2000;
int player_2_money = 2000;

boolean DEBUG_MODE = true;
boolean Dice_Rolled = false;
boolean nextTurn = true;
boolean gameOver = false;
boolean turnIsOver = false;
boolean doneMoving = false;
boolean SELL_HOUSE = false;
boolean BUY_HOUSE = false;
boolean playerHasRolled = false;
boolean TURN_OVER_PRESSED = false;
boolean TURN_OVER_BUTTON_IS_ON = false;
boolean cannotAfford = false;
boolean paidRent = false;
boolean player_1_wins = false;
boolean player_2_wins = false;
boolean TRAVERSING = false;
boolean INSERTION = false;
boolean DELETION = false;
boolean firstRound = true;

PVector player_1_pos;
PVector player_2_pos;
/**************************************************************************************/
House house1 = new House("Penny Lane", 1, 100.00f, 50.00f, 25.00f, 1);
House house2 = new House("Abbey Road", 2, 150.00f, 75.00f, 35.00f, 3);
House house3 = new House("Boardwalk", 3, 120.00f, 50.00f, 35.00f, 6);
House house4 = new House("Park Place", 4, 80.00f, 20.00f, 20.00f, 8);
House house5 = new House("Pennsylvania Av.", 5, 250.00f, 100.00f, 40.00f, 9);
House house6 = new House("Pacific Av.", 6, 200.00f, 80.00f, 50.00f, 11);
House house7 = new House("Marvin Gardens", 7, 210.00f, 145.00f, 70.00f, 13);
House house8 = new House("Atlantic Av.", 8, 300.00f, 200.00f, 90.00f, 14);
House house9 = new House("Illinois Av.", 9, 300.00f, 210.00f, 85.00f, 16);
House house10 = new House("New York Av.", 10, 230.00f, 150.00f, 80.00f, 18);
House house11 = new House("States Av.", 11, 240.00f, 120.00f, 100.00f, 19); 
House house12 = new House("St. Charles Pl.", 12, 400.00f, 300.00f, 150.00f, 21);
House house13 = new House("Oriental Av.", 13, 400.00f, 290.00f, 140.00f, 23);
House house14 = new House("Vermont Av.", 14, 500.00f, 380.00f, 220.00f, 24);
House house15 = new House("Baltic Av.", 15, 520.00f, 390.00f, 230.00f, 26);
House house16 = new House("St. James Av.", 16, 700.00f, 650.00f, 320.00f, 27);
House house17 = new House("Mediterranean Av.", 17, 700.00f, 650.00f, 350.00f, 29);
House house18 = new House("Tennessee Av.", 18, 710.00f, 640.00f, 280.00f, 31);
House house19 = new House("Ohio Av.", 19, 820.00f, 700.00f, 500.00f, 32);
House house20 = new House("Florida Av.", 20, 750.00f, 750.00f, 500.00f, 34);
House house21 = new House("New Jersey Av.", 21, 775.00f, 800.00f, 550.00f, 37);
House house22 = new House("Main Av.", 22, 900.00f, 800.00f, 650.00f, 39);

House getHouse( int i ) {
  switch(i) {
    case 1: return house1;
    case 2: return house2; 
    case 3: return house3; 
    case 4: return house4;
    case 5: return house5;
    case 6: return house6; 
    case 7: return house7; 
    case 8: return house8; 
    case 9: return house9; 
    case 10: return house10; 
    case 11: return house11; 
    case 12: return house12; 
    case 13: return house13; 
    case 14: return house14; 
    case 15: return house15; 
    case 16: return house16; 
    case 17: return house17; 
    case 18: return house18; 
    case 19: return house19; 
    case 20: return house20; 
    case 21: return house21; 
    case 22: return house22; 
    default: return null; 
  }
}
/*************************************************************************************/     
PVector[] GameBoardSlots = new PVector[40];
void initGameBoardSlots() {
  int x, y, i;
  // Left side slots
  x = 10;
  y = 295;
  for ( i = 0; i < 11; i++ ) {
     GameBoardSlots[i] = new PVector(x, y);
     if ( i == 0 || i == 9 ) y-= 30;
     else if ( i > 5 ) y -= 25;
     else  y -= 28;
  } 
  // Upper side slots
  x = 55;
  y = 15;
  for ( i = 11; i < 20; i++ ) {
     GameBoardSlots[i] = new PVector(x, y);
     x += 25;
  } 
  // right side slots
  x = 295;
  y = 15;
  for ( i = 20; i < 31; i++ ) {
     GameBoardSlots[i] = new PVector(x, y);
     if ( i == 20 || i == 30 ) y += 35;
     else if ( i > 27 ) y += 25;
     else y += 27;
  }
  // bottom side slots
  x = 260;
  y = 295;
  for ( i = 31; i < 40; i++ ) {
     GameBoardSlots[i] = new PVector(x, y);
     if ( i > 36 ) x -= 30;
     else x -= 25;
  }
}
/************************************************************************************/      
void setup() {
  size(818, 780);
  
  serif36 =               loadFont("AlBayan-36.vlw");
  serif24 =               loadFont("AlBayan-24.vlw");
  serif16 =               loadFont("Serif-16.vlw");
  
  gameboard =             loadImage("gameboard.png");
  house =                 loadImage("house.png");
  buy_button =            loadImage("buy_button.png");
  buy_button_pressed =    loadImage("buy_button_pressed.png");
  sell_button =           loadImage("sell_button.png");
  sell_button_pressed =   loadImage("sell_button_pressed.png");
  roll_button =           loadImage("roll_button.png");
  roll_button_pressed =   loadImage("roll_button_pressed.png");
  inactive_button =       loadImage("inactive_button.png");
  node_selector =         loadImage("node_selector.png");
  player_1 =              loadImage("player_1.png");
  player_2 =              loadImage("player_2.png");
  dice_null =             loadImage("dice_null.png");
  dice_1 =                loadImage("dice_1.png");
  dice_2 =                loadImage("dice_2.png");
  dice_3 =                loadImage("dice_3.png");
  dice_4 =                loadImage("dice_4.png");
  dice_5 =                loadImage("dice_5.png");
  dice_6  =               loadImage("dice_6.png");
  turn_over_button =      loadImage("turn_over_button.png");
  turn_over_button_pressed = loadImage("turn_over_button_pressed.png");
  arrow_link =            loadImage("arrow.png");
  
  // initialize game board slots
  initGameBoardSlots();
  
  // default positions set
  player_1_pos = GameBoardSlots[0];
  player_2_pos = GameBoardSlots[0];
  
  frameRate(2);
  
}

/*******************************///////////////////////////
                                /*       GAME LOOP       */
                                ///////////////////////////************************************/
void draw() {
  
  if (START_BANK_WITH_HOUSES ) {
    Bank.add(getHouse(8)); getHouse(8).owned_by = BANK;
    Bank.add(getHouse(9)); getHouse(9).owned_by = BANK;
    Bank.add(getHouse(12)); getHouse(12).owned_by = BANK;
    Bank.add(getHouse(15)); getHouse(15).owned_by = BANK;
    START_BANK_WITH_HOUSES = false;
  }
  
  if (START_PLAYER_1_WITH_HOUSES ) {
    Player_1.add(getHouse(1)); getHouse(1).owned_by = 1;
    Player_1.add(getHouse(3)); getHouse(3).owned_by = 1;
    Player_1.add(getHouse(4)); getHouse(4).owned_by = 1;
    START_PLAYER_1_WITH_HOUSES = false;
  }
  
  if (START_PLAYER_2_WITH_HOUSES ) {
    Player_2.add(getHouse(2)); getHouse(2).owned_by = 2;
    Player_2.add(getHouse(5)); getHouse(5).owned_by = 2;
    Player_2.add(getHouse(6)); getHouse(6).owned_by = 2;
    START_PLAYER_2_WITH_HOUSES = false;
  }
  
  // Draw background at each frame
  background(gameboard);
  
  // While game is not over:
  if ( !gameOver ) {
     // Displaye Game State
     DisplayGameComponents();
     
   if (DEBUG_MODE) { 
     if (TRAVERSING) 
       println("Still traversing, INSERTION="+INSERTION+", DELETION="+DELETION);
   }
   // check if we still need to animate any traversions
   if ( !TRAVERSING ) {  
     
     // Wait for player to roll the dice
     if ( Dice_Rolled ) {
          Dice_Rolled = false; // reset dice flag
          image(roll_button, ROLL_BUTTON_X, ROLL_BUTTON_Y);
          // randomly choose the dice roll
          roll = int(random(1, 7));
          if (DEBUG_MODE) println("Player_"+Turn+" rolls a "+roll);
          turnIsOver = false;
          playerHasRolled = true;
          cannotAfford = false;
          paidRent = false;
     }
     
      // while turn is not over
      if ( !turnIsOver ) {
        // Display the current moves left
        DisplayDice(roll);
        
        // move current player acording to rolled dice
        if ( roll > 0 ) {
          MovePlayer();
          roll--;
          doneMoving = false;
        } else doneMoving = true;
        
        // Update player's position
        DisplayPlayers(); 
        
        // firstly, check if player's have passed the "GO" tile
        if ( roundCount > 1 ) {firstRound = false;}
        if ( PlayerLandedOnGO() && !firstRound && playerHasRolled ) {
           addMoneyToPlayer((float)REWARD, false); 
           if (DEBUG_MODE) println("Player"+Turn+" gets rewarded $"+REWARD);
           if ( roundCount > 2 ) roundCount = 0; // reset
           if (doneMoving) roundCount = 0;
        }

        // Wait for player to stop moving
        if ( playerHasRolled && doneMoving ) {
          /*                                                              */
          /* If player lands on a house slot, determine wheter it's hers  */
          /* if it is not hers and it's owned by the other player, then   */
          /* she must pay rent. Otherwise, she has the option to buy      */
          /*                                                              */
          
          // check if player landed on a house
          int house = PlayerLandedOnHouse();
          if ( house != -1 ) { 
            String name = getHouse(house).name;
            int owner = getHouse(house).owned_by;
            if ( owner != Turn ) { // This is not her house
              if ( owner == NONE || owner == BANK ) { // Owned by either the bank or no owner
                float price = getHouse(house).buy_price;
                
                // Can player afford this house?
                if ( !canAfford(price) ) { 
                  // cannot afford
                  turnIsOver = true;
                  cannotAfford = true;
                }
                // can buy
                else {
                  // Display "BUY" button
                  image(buy_button, BUY_BUTTON_X, BUY_BUTTON_Y);
                  // prompt player
                  text("You can buy this house for $"+price+"0",TEXT_FIELD_POS.x, TEXT_FIELD_POS.y);
                  DisplayHouseInfo(house);
                  
                  // Give the player the option to pass
                  TURN_OVER_BUTTON_IS_ON = true; // for input handling
                  image(turn_over_button, TURN_OVER_BUTTON_X, TURN_OVER_BUTTON_Y);
                  
                  // ask to buy house or pass
                  if ( BUY_HOUSE ) {
                    // Player has chosen to buy the house
                    //text("Player buys house for $"+price+"0",TEXT_FIELD_POS.x, TEXT_FIELD_POS.y+LS);
                    if (DEBUG_MODE) println("Player_"+Turn+" buys "+name+" for $"+price);
                    
                    // deduct the amount of money from the player
                    deductFromPlayer(price);
                    
                    // Set the hose owner to the current player
                    getHouse(house).owned_by = Turn;
                    
                    // Tell the game the turn is over
                    turnIsOver = true;
                    BUY_HOUSE = false; // reset paranoia?
                    
                    /* If the owner is the bank, then we need to first remove from bank  */
                    /* By passing false as second parameter, we handle insertion to      */
                    /* player's linked list.                                             */
                    //
                    if ( owner == BANK ) {
                      // Turn on traversing mode to plause the game for
                      // the next few frames
                      TRAVERSING = true;
                      // delete from bank
                      // Second parameter check if we insert to bank
                      if (DEBUG_MODE) println("Deleting from bank");
                      DELETING_FROM_BANK = true;
                      //
                      deleteFromLinkedList(getHouse(house), true);
                      // insert to player's list
                      //insertToLinkedList(getHouse(house), false);
                    }
                    else { // no one owns the house
                      // Insert to the player's linked list records
                      TRAVERSING = true;
                      insertToLinkedList(getHouse(house), false);
                    }
                  } else if ( TURN_OVER_PRESSED ) turnIsOver = true; // player passed
                }
              } // House owned by someone, and no the bank so...
              else {               
                // owned by other player
                if (  owner != BANK ) { // Paranoia?
                   // This player owes money!!
                   float rent = getHouse(house).rent_price;
                   text("Player pays rent at rate of $"+rent+"0", TEXT_FIELD_POS.x, TEXT_FIELD_POS.y);
                   if (DEBUG_MODE) println("Player_"+Turn+" rents "+name+" for $"+rent);
                   
                   deductFromPlayer(rent);
                   addMoneyToPlayer(rent, true);
                   turnIsOver = true;
                   paidRent = true;
                }
              }
            } 
            else { 
              // the house is her's, give the option to sell
              if ( owner == Turn ) { // affirm
              
                image(sell_button, SELL_BUTTON_X, SELL_BUTTON_Y);
                float price = getHouse(house).sell_price;
                text("You can sell this house for $"+price+"0", TEXT_FIELD_POS.x, TEXT_FIELD_POS.y);
                
                DisplayHouseInfo(house);
                
                TURN_OVER_BUTTON_IS_ON = true;
                image(turn_over_button, TURN_OVER_BUTTON_X, TURN_OVER_BUTTON_Y);
                
                if ( SELL_HOUSE ) {
                   //text("Player sells house for $"+price+"0",TEXT_FIELD_POS.x, TEXT_FIELD_POS.y+LS);
                   if (DEBUG_MODE) println("Player"+Turn+" sells "+name+" for $"+price+"0");
                   
                   addMoneyToPlayer(price, false);
                   
                   getHouse(house).owned_by = 3; // bank owns it now
                   turnIsOver = true; 
                   SELL_HOUSE = false; //reset
                   
                   // We now delete the house node from the player's list
                   // and insert it back to the bank's list
                   INSERTING_TO_BANK = true;

                   // delelte from player's list
                   deleteFromLinkedList(getHouse(house), false);
                   
                   // insert to bank's list
                   // insertToLinkedList(getHouse(house), true);
                   
                   
                } else if ( TURN_OVER_PRESSED ) turnIsOver = true; // player passed
              }
            }
          } ///////////// Did not land on a house //////////////
          else {
            if ( !TRAVERSING ) {
              turnIsOver = true;
              roundCount++;
            }
          }
          
        } // turn is not over
        
      }// turn is over
       
      // Reset flags at end of every turn
      if ( ((playerHasRolled && doneMoving && turnIsOver) || TURN_OVER_PRESSED ) && !TRAVERSING ) {
        
        ToggleTurn();
        resetGameState();
        
      }
      
      // make sure turn is over by now
      turnIsOver = false;
      
      // Check if game is over
      checkForGameOver();
      
     }
     
     /**** STILL TRAVERSING *****/
     
     else if ( INSERTION ) {
       // display players is skipped, so make sure they are still displayed
        DisplayPlayers(); 
       // keep doing insertion animation
       if (DEBUG_MODE) println("Calling insertion. INSERTING_TO_BANK = "+INSERTING_TO_BANK);
       insertToLinkedList(null, INSERTING_TO_BANK);
     }
     
     else if ( DELETION ) {
       // display players is skipped, so make sure they are still displayed
        DisplayPlayers(); 
       // keep doing deletion animation
       if (DEBUG_MODE) println("Calling deletion. DELETING_FROM_BANK = "+DELETING_FROM_BANK);
       deleteFromLinkedList(null, DELETING_FROM_BANK);
     }
     
  } // game over
  
  else { 
     // Game is over
     displayGameIsOver();
  }
  
} // End of main loop

/*****************************///////////////////////////
                              /*    GAMEBOARD LOGIC    */
                              ///////////////////////////**********************************/

/***************************************************/
void MovePlayer() {
  int pos;
  if ( Turn == 1 ) {
     pos = findPlayerPosOnBoard(player_1_pos);
     if (pos != -1 ) {
       if ( pos == 39 ) pos = -1;
       if ( pos == 40 ) pos = 0;
       player_1_pos = GameBoardSlots[++pos];
     }
     else println("Error in moving player");
  }
  else {
     pos = findPlayerPosOnBoard(player_2_pos);
     if (pos != -1 ) {
       if ( pos == 39 ) pos = -1;
       if ( pos == 40 ) pos = 0;
       player_2_pos = GameBoardSlots[++pos];
     }
     else println("Error in moving player");
  } 
}

/***************************************************/
int findPlayerPosOnBoard(PVector player_pos) {
  for ( int i=0; i < 41; i++ ) {
     if ( player_pos.x == GameBoardSlots[i].x )
       if ( player_pos.y == GameBoardSlots[i].y )
         return i;
  }
  return -1;
}

/***************************************************/
boolean PlayerLandedOnGO() {
  if (Turn == 1 ) {
    if ( player_1_pos.x == GameBoardSlots[0].x )
      if ( player_1_pos.y == GameBoardSlots[0].y ) 
        return true;
  }
  else {
    if ( player_2_pos.x == GameBoardSlots[0].x )
      if ( player_2_pos.y == GameBoardSlots[0].y ) 
        return true;
  }
  
  return false;
}


/***************************************************/
int PlayerLandedOnHouse() {
  int i;
  if (Turn == 1 ) {
    for (i=1; i<23; i++) {
      if ( player_1_pos.x == GameBoardSlots[getHouse(i).slot_location].x )
        if ( player_1_pos.y == GameBoardSlots[getHouse(i).slot_location].y ) 
          return i;
    }
  }
  else {
     for (i=1; i<23; i++) {
      if ( player_2_pos.x == GameBoardSlots[getHouse(i).slot_location].x )
        if ( player_2_pos.y == GameBoardSlots[getHouse(i).slot_location].y ) 
          return i;
    }
  }
  
  return -1;
}

/***************************************************/
void resetGameState() {
  playerHasRolled = false;
  BUY_HOUSE = false;
  SELL_HOUSE = false;
  TURN_OVER_PRESSED = false;
  Dice_Rolled = false; // reset dice flag
}

/******************************///////////////////////////
                                /*      MONEY LOGIC      */
                                ///////////////////////////***********************************/
                                

/***************************************************/
boolean canAfford(float pr) {
   if ( Turn == 1 ) {
    if ( player_1_money < pr ) {
       text("You cannot afford this house.",  TEXT_FIELD_POS.x, TEXT_FIELD_POS.y);
       return false;
    } 
   }
   else if ( player_2_money < pr ) {
     text("You cannot afford this house.",  TEXT_FIELD_POS.x, TEXT_FIELD_POS.y);
     return false;
   }
   // else
   return true;
}

/***************************************************/
void ToggleTurn() {
  if (Turn == 1 ) Turn = 2;
  else Turn = 1;
}

/***************************************************/
void AddRewardToPlayer() {
  if (Turn==1) player_1_money += REWARD;
  else player_2_money += REWARD;
}

/***************************************************/
void addMoneyToPlayer(float pr, boolean other) {
  if (!other) {
    if (Turn == 1) player_1_money += pr;
    else player_2_money += pr; 
  }
  else {
    if (Turn == 1) player_2_money += pr;
    else player_1_money += pr; 
  }
}

/***************************************************/
void deductFromPlayer(float pr) { 
  if (Turn == 1) player_1_money -= pr;
  else player_2_money -= pr;
}

/*********************************///////////////////////////
                                  /*    GAME STATE LOGIC   */
                                  ///////////////////////////******************************/


/***************************************************/
void checkForGameOver() {
  if ( player_1_money < 0 ) {
        DisplayGameComponents();
        text("Game Over: Player 2 wins.", TEXT_FIELD_POS.x, TEXT_FIELD_POS.y);
        player_2_wins = true;
        gameOver = true;
        
  } else if ( player_2_money < 0 ) {
        DisplayGameComponents();
        text("Game Over: Player 1 wins.", TEXT_FIELD_POS.x, TEXT_FIELD_POS.y);
        player_1_wins = true;
        gameOver = true;
  }
}

/***************************************************/
void displayGameIsOver() {
  DisplayGameComponents();
  if (player_1_wins ) text("Game Over: Player 1 wins.", TEXT_FIELD_POS.x, TEXT_FIELD_POS.y);
  else text("Game Over: Player 2 wins.", TEXT_FIELD_POS.x, TEXT_FIELD_POS.y);
}

/*******************************///////////////////////////
                                /*      GAME DSPLAYS     */
                                ///////////////////////////**********************************/
                                

/***************************************************/
void DisplayGameComponents() {
 if ( !playerHasRolled ) image(roll_button, ROLL_BUTTON_X, ROLL_BUTTON_Y);
 image(dice_null, DICE_X_POS, DICE_Y_POS);
 DisplayTurn();
 DisplayPlayerScores();
 if ( cannotAfford ) 
   text("Could not afford to buy.",  TEXT_FIELD_POS.x, TEXT_FIELD_POS.y+LS);
 
 if ( paidRent )
   text("Previous player paid rent.",  TEXT_FIELD_POS.x, TEXT_FIELD_POS.y+LS);

 
 int step = 0;
 ListIterator itr = Player_1.listIterator(step);
 while ( itr.hasNext() ) {
     image(house, PLAYER_1_LIST_X + ( step * 70 ) + 5, PLAYER_1_LIST_Y+ 5);
     step++;
     itr.next();
 }
 step = 0;
 itr = Player_2.listIterator(step);
 while ( itr.hasNext() ) {
     image(house, PLAYER_2_LIST_X + ( step * 70 ) + 5, PLAYER_2_LIST_Y+ 5);
     step++;
     itr.next();
 }
 
 step = 0;
 itr = Bank.listIterator(step);
 while ( itr.hasNext() ) {
     image(house, BANK_LIST_X + ( step * 70 ) + 5, BANK_LIST_Y+ 5);
     step++;
     itr.next();
 }
 
 
}

void DisplayHouseInfo(int i) {
  House h = getHouse(i);
  text("Property: "+h.name,TEXT_FIELD_POS.x, TEXT_FIELD_POS.y+LS*2);
  text("Buy Price: $"+h.buy_price+"0",TEXT_FIELD_POS.x, TEXT_FIELD_POS.y+LS*3);
  text("Sell Price: $"+h.sell_price+"0",TEXT_FIELD_POS.x, TEXT_FIELD_POS.y+LS*4);
  text("Rent: $"+h.rent_price+"0",TEXT_FIELD_POS.x, TEXT_FIELD_POS.y+LS*5);
}

/***************************************************/
void DisplayPlayers() {
   image(player_1, player_1_pos.x-10, player_1_pos.y-5);
   image(player_2, player_2_pos.x-10, player_2_pos.y-5); 
}

/***************************************************/
void DisplayTurn() {
  textFont(serif24, 24);
  fill(TEXT_COL);
  if ( Turn == 1 ) text("Player 1", PLAYER_TURN_X, PLAYER_TURN_Y);
  else text("Player 2", PLAYER_TURN_X, PLAYER_TURN_Y); 
}

/***************************************************/
void DisplayPlayerScores() {
  textFont(serif24, 20);
  fill(#292934);
  //
  if ( player_1_money > 0 ) text("$"+player_1_money, 15, 430);
  else {
    fill(BANKRUPT_COL);
    text("BANKRUPT", 5, 440);
    fill(TEXT_COL);
    gameOver = true;
  }
  //
  if ( player_2_money > 0 ) text("$"+player_2_money, 15, 562); 
  else {
    fill(BANKRUPT_COL);
    text("BANKRUPT", 5, 590);
    fill(TEXT_COL);
    gameOver = true;
  }
  // 
  fill(TEXT_COL);
  textFont(serif16, 16);
}

/***************************************************/
void DisplayDice(int r) {
   switch(r) {
    case 1: image(dice_1, DICE_X_POS, DICE_Y_POS); break;
    case 2: image(dice_2, DICE_X_POS, DICE_Y_POS); break;
    case 3: image(dice_3, DICE_X_POS, DICE_Y_POS); break;
    case 4: image(dice_4, DICE_X_POS, DICE_Y_POS); break;
    case 5: image(dice_5, DICE_X_POS, DICE_Y_POS); break;
    case 6: image(dice_6, DICE_X_POS, DICE_Y_POS); break;
    default: image(dice_null, DICE_X_POS, DICE_Y_POS); break;
   } 
}


/*******************************///////////////////////////
                                /*    INPUT HANDLERS     */
                                ///////////////////////////***********************************/

/***************************************************/
void mouseClicked() {
  if ( !playerHasRolled ) {
    if ( mouseX < (ROLL_BUTTON_X + 164) && mouseX > ROLL_BUTTON_X ) {
       if ( mouseY < (ROLL_BUTTON_Y + 43) && mouseY > ROLL_BUTTON_Y ) {
         image(roll_button_pressed, ROLL_BUTTON_X, ROLL_BUTTON_Y);
         Dice_Rolled = true;
       }
    } 
  }
  
  int house = PlayerLandedOnHouse();
  if ( house != -1 && doneMoving ) {
    int owner = getHouse(house).owned_by;
    if (  owner == Turn  ) {
      if ( mouseX > SELL_BUTTON_X && mouseX < SELL_BUTTON_X+164) {
         if ( mouseY > SELL_BUTTON_Y && mouseY < SELL_BUTTON_Y+43) {
           image(sell_button_pressed, SELL_BUTTON_X, SELL_BUTTON_Y);
           SELL_HOUSE = true;    
         }
      } 
    }
    else if ( (Turn == 1 && owner != 2) || (Turn == 2 && owner != 1) ) {  
      // if owner is not the other player
      if ( mouseX > BUY_BUTTON_X && mouseX < BUY_BUTTON_X+164) {
         if ( mouseY > BUY_BUTTON_Y && mouseY < BUY_BUTTON_Y+43) {
           image(buy_button_pressed, BUY_BUTTON_X, BUY_BUTTON_Y);
           BUY_HOUSE = true;    
         }
      }
    } 
  }
  
  if ( TURN_OVER_BUTTON_IS_ON ) {
    if ( mouseX > TURN_OVER_BUTTON_X && mouseX < TURN_OVER_BUTTON_X+164) {
       if ( mouseY > TURN_OVER_BUTTON_Y && mouseY < TURN_OVER_BUTTON_Y+43) {
         image(turn_over_button_pressed, TURN_OVER_BUTTON_X, TURN_OVER_BUTTON_Y);
         TURN_OVER_PRESSED = true;
         TURN_OVER_BUTTON_IS_ON = false;
       }
    }
  }
  
}

/*****************************///////////////////////////
                              /* LINKED-LISTS HANDLERS */
                              ///////////////////////////**********************************/
                              
void insertToLinkedList(House h, boolean bank) {
  /* To insert a house:
  /*       1. Check which linked list to insert the house to                     */
  /*       2. Iterate through the linked list untill we reach a null node        */
  /*          a. at each iteration, we display the iterator (and house name)     */
  /*          b. Once we find the end of the list, we keep the iterator on,
  /*             and we add a house image                                        */
  /*       3. Do not show the iterator anymore and keep the new house on display */
  int X_POS, Y_POS;
  TRAVERSING = true;
  frameRate(1);
  
  // cache our current house for next frames
  if ( h != null ) INSERTION_HOUSE = h;
  // If h == null, then we have a pending animation.
  // To Handle continued animation:
  // INSERTION_STEP -> the index we are on the list
  
  // Start an iterator at the current step
  ListIterator itr;
  if ( bank ) {
    if (DEBUG_MODE) println("INSERTION: Setting iterator for Bank's list at "+INSERTION_STEP);
    itr = Bank.listIterator(INSERTION_STEP); 
    X_POS = BANK_LIST_X;
    Y_POS = BANK_LIST_Y;
  }
  else if ( Turn == 1 ) {
    if (DEBUG_MODE) println("INSERTION: Setting iterator for Player_1's list at "+INSERTION_STEP);
    itr = Player_1.listIterator(INSERTION_STEP); 
    X_POS = PLAYER_1_LIST_X;
    Y_POS = PLAYER_1_LIST_Y;
  }
  else  {
    if (DEBUG_MODE) println("INSERTION: Setting iterator for Player_2's list at "+INSERTION_STEP);
    itr = Player_2.listIterator(INSERTION_STEP);
    X_POS = PLAYER_2_LIST_X;
    Y_POS = PLAYER_2_LIST_Y;
  }
 
  // Iterate from first element and check if it is null
  // if the node is null, we insert a house
  if ( itr.hasNext() ) {
    if (DEBUG_MODE) println("INSERTION: Not at the end of the list yet...");
    // Display the node iterator image at itr position
    image(node_selector, X_POS + (INSERTION_STEP * 70), Y_POS);
    // Turn on INSERTION MODE to pause the game next time around
    INSERTION = true;
    TRAVERSING = true;
    if (bank) {
      INSERTING_TO_BANK = true;
    }
    // Increment iteration point
    INSERTION_STEP++;
    if (DEBUG_MODE) println("Increment node to "+INSERTION_STEP);
  }
  else {
    // insert house 
    image(node_selector, X_POS + (INSERTION_STEP * 70), Y_POS);
    image(house, X_POS + (INSERTION_STEP * 70) +5, Y_POS+5);
    
    if ( bank ) {
      Bank.add(INSERTION_HOUSE);
      INSERTING_TO_BANK = false; // reset flag that may have been activated
      if (DEBUG_MODE) println("Added "+INSERTION_HOUSE.name+" to the bank's list");
    }
    else if ( Turn == 1 ) {
      Player_1.add(INSERTION_HOUSE);
      if (DEBUG_MODE) println("Added "+INSERTION_HOUSE.name+" to Player_1's list");
    }
    else {
      Player_2.add(INSERTION_HOUSE);
      if (DEBUG_MODE) println("Added "+INSERTION_HOUSE.name+" to the Player_2's list");
    }
    
    // reset if necessary
    if ( INSERTION_STEP > 0 ) { 
        ToggleTurn();
        resetGameState();
     }
    // unpause game
    if ( INSERTING_TO_BANK ) INSERTING_TO_BANK = false;
    TRAVERSING = false;
    INSERTION = false;
    INSERTION_STEP = 0;
    INSERTION_HOUSE = null;
    frameRate(2);
  }
  
  if ( INSERTING_TO_BANK ) {
    TRAVERSING = true;
    INSERTION = true;
  }
  
}

void deleteFromLinkedList(House h, boolean bank) {
  /* INSERTING_TO_BANK makes sure we are inserting this sam ehouse to the bank.     */
  /*                                                                                */
  /* The proceedure iterates throught the current player's list of houses untill    */
  /* the desired house to delete is reached. Once it is reached, we show a symbolic */
  /* link from the previous node to the next house's node, then we remove the       */
  /* house from the list, and finally remove the symbolic link image and move all   */
  /* the houses to the right of the house deleted to the left one slot.             */
  int X_POS, Y_POS;
  // Turn on traversing to pause the game
  TRAVERSING = true;
  frameRate(1);
  
  // cache our current house for next frames
  if ( h != null ) DELETION_HOUSE = h;
  
  // Decide which link list to use
   ListIterator itr;
  if ( bank ) {
    if (DEBUG_MODE) println("DELETION: Initialize Bank's list iterator at "+DELETION_STEP);
    itr = Bank.listIterator(DELETION_STEP); 
    X_POS = BANK_LIST_X;
    Y_POS = BANK_LIST_Y;
  }
  else if ( Turn == 1 ) {
    if (DEBUG_MODE) println("DELETION: Initialize PLayer_1's list iterator at "+DELETION_STEP);
    itr = Player_1.listIterator(DELETION_STEP); 
    X_POS = PLAYER_1_LIST_X;
    Y_POS = PLAYER_1_LIST_Y;
  }
  else {
    if (DEBUG_MODE) println("DELETION: Initialize PLayer_2's list iterator at "+DELETION_STEP);
    itr = Player_2.listIterator(DELETION_STEP);
    X_POS = PLAYER_2_LIST_X;
    Y_POS = PLAYER_2_LIST_Y;
  }
  //
  
  if ( itr.hasNext() ) {
    // while this is not the houe we want to delete
    House ho = (House)itr.next();
    if ( ho.name != DELETION_HOUSE.name ) {
      if (DEBUG_MODE) println("DELETION: Has not reached the correct house yet...");
      // Display the node iterator image at itr position
      image(node_selector, X_POS + (DELETION_STEP * 70), Y_POS);
      // Turn on INSERTION MODE to pause the game next time around
      DELETION = true;
      TRAVERSING = true;
      // Increment iteration point
      DELETION_STEP++;
      if (DEBUG_MODE) println("Increment node to "+DELETION_STEP);
    }
    else {
      // We have found the house to delete
      // Display the node iterator image at itr position
      image(node_selector, X_POS + (DELETION_STEP * 70), Y_POS);
      if ( DELETION_STEP > 0 ) image(arrow_link, X_POS + (DELETION_STEP * 70) - 50, Y_POS - 50);
      
      if ( bank ) {
        // Remove house from list
        Bank.remove(DELETION_STEP);
        if (DEBUG_MODE) println(DELETION_HOUSE.name+" has been removed from bank's list"); 
        // we are deleting from the bank, which means someone bought the house back
        // insert house to player's list
        insertToLinkedList(DELETION_HOUSE, false);        
      }
      else if ( Turn == 1 ) {
        // Remove house from list
        Player_1.remove(DELETION_STEP);
        if (DEBUG_MODE) println(DELETION_HOUSE.name+" has been removed from Player_1's list");
      }
      else  {
        // Remove house from list
        Player_2.remove(DELETION_STEP);
        if (DEBUG_MODE) println(DELETION_HOUSE.name+" has been removed from PLayer_2's list");
      }
      
      // If this house was sold, we insert it to the bank
      if ( INSERTING_TO_BANK ) {
        if (DEBUG_MODE) println("calling method to insert "+DELETION_HOUSE.name+" to the bank's list");
        insertToLinkedList(DELETION_HOUSE, true);
      }
      
      // reset if necessary
      if ( DELETION_STEP > 0 ) { 
          ToggleTurn();
          resetGameState();
      }
      // Unless we are inserting to or deleting from the bank, unpause game
      if ( !INSERTING_TO_BANK ) TRAVERSING = false;
      DELETION = false;
      DELETION_STEP = 0;
      DELETION_HOUSE = null;
      frameRate(2);
    }
  } // has next iterator
}